#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include "Mutex.hpp"
#include <filesystem> //c++17
#include <fstream>
#include <sstream>
#include <memory>
#include <time.h>
#include <cstdio>
namespace LogMudule
{
    using namespace LockModule;
    // 获取当前时间
    std::string CurrentTime()
    {
        //获取当前时间戳
        time_t time_stamp = ::time(nullptr);

        struct tm curr;
        // 把时间戳转换成curr
        localtime_r(&time_stamp, &curr);

        char buffer[1024];
        snprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d:%02d:%02d",
                 curr.tm_year+1900,
                 curr.tm_mon+1,
                 curr.tm_mday,
                 curr.tm_hour,
                 curr.tm_min,
                 curr.tm_sec);
        return buffer;
    }
    // 构成: 1.构建日志字符串  2.刷新落盘(screen，file)
    const std::string defaultlogpath = "./log/";
    const std::string defaultlogname = "log.txt";

    // 2.日志等级
    enum class LogLevel
    {
        DEBUG = 1,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    std::string Level2String(LogLevel level)
    {
        switch (level)
        {
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::WARNING:
            return "WARNING";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::FATAL:
            return "FATAL";
        default:
            return "None";
        }
    }

    // 3.刷新策略
    class LogStrategy
    {
    public:
        virtual ~LogStrategy() = default;
        virtual void SyncLog(const std::string &message) = 0;
    };

    // 3.1控制台策略
    class ConsoleLogStrategy : public LogStrategy
    {
    public:
        ConsoleLogStrategy()
        {
        }
        ~ConsoleLogStrategy()
        {
        }

        void SyncLog(const std::string &message)
        {
            Lockguard lockguard(_lock);
            std::cout << message << std::endl;
        }

    private:
        Mutex _lock;
    };
    // 3.2磁盘级策略
    class FileLogStrategy : public LogStrategy
    {
    public:
        FileLogStrategy(const std::string &logpath = defaultlogpath, const std::string &logname = defaultlogname)
            : _logpath(logpath),
              _logname(logname)
        {
            // 确认_logpath是存在的.
            Lockguard lockguard(_lock);

            if (std::filesystem::exists(_logpath))
            {
                return;
            }
            try
            {
                std::filesystem::create_directories(_logpath);
            }
            catch (std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << "\n";
            }
        }
        ~FileLogStrategy()
        {
        }
        void SyncLog(const std::string &message)
        {
            Lockguard lockguard(_lock);
            std::string log = _logpath + _logname;
            // 和c一样，c的stdout表示输出流
            // c++把流封装到的ios对象中
            // 有输出流ofstream(文件中写入)
            // 输入流ifstream
            //std::ios内部封装了读写...模式，类似于系统调用中的宏
            //c中的fopen中的r，w封装了系统调用的宏，c++中的ios库中封装了系统调用的宏
            std::ofstream out(log, std::ios::app);
            if (!out.is_open())
            {
                return;
            }
            out << message << "\n";

            out.close();
        }

    private:
        std::string _logpath;
        std::string _logname;

        Mutex _lock;
    };

    // 4.日志类:构建日志字符串，根据策略 ，进行刷新
    class Logger
    {
    public:
        Logger()
        {
            // 默认采用ConsoleLogStrategy策略
            _strategy = std::make_shared<ConsoleLogStrategy>();
        }
        void EnableConsoleLog()
        {
            _strategy = std::make_shared<ConsoleLogStrategy>();
        }

        void EnableFileLog()
        {
            _strategy = std::make_shared<FileLogStrategy>();
        }
        ~Logger()
        {
        }
        // 一条完整的信息  日志的标准部分+日志的可变部分(<<"hello world"<<3.14<<a<<b;)

        class LogMessage
        {
        public:
            LogMessage(LogLevel level, const std::string &filename, int line, Logger &logger)
                : _currtime(CurrentTime()), _level(level), _pid(::getpid()), _filename(filename), _line(line), _logger(logger)
            {
                std::stringstream ssbuffer;
                ssbuffer << "[" << _currtime << "]"
                         << "[" << Level2String(_level) << "]"
                         << "[" << _pid << "]"
                         << "[" << _filename << "]"
                         << "[" << _line << "] - ";
                _loginfo = ssbuffer.str();
            }
            template <typename T>
            LogMessage &operator<<(const T &info)
            {
                std::stringstream ss;
                ss << info;//全部插入到流里
                _loginfo += ss.str();
                return *this;
            }

            ~LogMessage()
            {
                if (_logger._strategy)
                {
                    _logger._strategy->SyncLog(_loginfo);
                }
            }

        private:
            std::string _currtime;
            LogLevel _level;
            pid_t _pid;            // 进程pid
            std::string _filename; // 源文件名称
            uint32_t _line;        // 32位无符号整数类型，日志所在行号

            Logger &_logger;      // 对当前logger对象的引用
            std::string _loginfo; // 一条完整的日志记录
        };

        // 故意返回的是创建的临时对象，因为对于每一条日志都要创建一个自己的LogMessage，
        // 得到自己的LogMessage后，经过<<运算符重载，再对自己专属的LogMessage进行修改
        LogMessage operator()(LogLevel level, const std::string &filename, int line)
        {
            return LogMessage(level, filename, line, *this);
        }

    private:
        std::shared_ptr<LogStrategy> _strategy; // 日志刷新的策略方案
    };

    Logger logger;

#define LOG(level) logger(level, __FILE__, __LINE__)
#define ENABLE_CONSOLE_LOG() logger.EnableConsoleLog();
#define ENABLE_FILE_LOG() logger.EnableFileLog();

}

// 写一个日志  [2024-11-25 18:43:16][DEBUG][714658][Main.cc][9] - hello world(这种类型的)

/*#pragma once
#include <iostream>
#include <string>
#include "Mutex.hpp"
#include <filesystem> //c++17
#include <fstream>
#include <sstream>
#include <time.h>
#include <memory>

namespace LogModule
{
    // 希望日志存放的路径，只需要写出相对路径，绝对路径会根据环境变量补齐

    std::string Currentime()
    {
        time_t time_shamp = time(nullptr);
        struct tm curr;

        localtime_r(&time_shamp, &curr);

        char buffer[1024];
        snprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d:%02d:%02d",
                 curr.tm_year + 1900,
                 curr.tm_mon + 1,
                 curr.tm_mday,
                 curr.tm_hour,
                 curr.tm_min,
                 curr.tm_sec);
        return buffer;
    }

    std::string Level2String(LogLevel level)
    {
        switch (level)
        {
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::WARNING:
            return "WARNING";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::FATAL:
            return "FATAL";
        default:
            return "None";
        }
    }

    const std::string &_defaultlogpath = "./log/";
    const std::string &_defaultlogname = "log.txt";

    using namespace LockModule;
    enum class LogLevel
    {
        DEBUG = 1,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    class LogMode
    {
    public:
        virtual ~LogMode() = default;
        virtual void SyncLog(const std::string &Message) = 0;
    };

    // 控制台模式
    class ConsoleLogMode : public LogMode
    {
    public:
        ~ConsoleLogMode() = default;
        // 直接刷新到控制台上
        virtual void SyncLog(const std::string &Message)
        {
            Lockguard lockguard(_mutex);
            std::cout << Message << std::endl;
        }

    private:
        Mutex _mutex;
    };

    // 刷新到指定的文件中
    class FileLogMode : public LogMode
    {
    public:
        // 在Logger，可以调用成员对象，利用智能指针构建一个FileLogMode赋值给之前的Mode模式//
        FileLogMode(const std::string &logpath = _defaultlogpath, const std::string &logname = _defaultlogname)
            : _logpath(logpath), _logname(logname)
        {
            Lockguard lockguard(_mutex);

            if (std::filesystem::exists(_logpath))
            {
                return;
            }
            try
            {
                std::filesystem::create_directories(_logpath);
            }
            catch (std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << "\n";
            }
        }
        ~FileLogMode()
        {
        }
        // c++如何打开指定的文件，并且把内容写到文件里面的
        virtual void SyncLog(const std::string &Message)
        {
            std::string DesignateFile = _logpath + _logname;
            std::ofstream out(DesignateFile, std::ios::app);
            if (!out.is_open())
            {
                return;
            }
            else
            {
                out << Message << "\n";
            }
        }

    private:
        std::string _logpath;
        std::string _logname;
        Mutex _mutex;
    };

    class Logger
    {
    public:
        Logger()
        {
            //默认使用控制台Mode
            Mode_ptr = std::make_shared<ConsoleLogMode>();
        }
        void ConsoleMode()
        {
            Mode_ptr = std::make_shared<ConsoleLogMode>();
        }
        void FileMode()
        {
            Mode_ptr = std::make_shared<FileLogMode>();
        }
        ~Logger()
        {

        }

        class LogMessage
        {
            LogMessage()
            {

            }

            ~LogMessage()
            {

            }


        };




    private:
        //一个指向Mode的智能指针
        std::shared_ptr<LogMode> Mode_ptr;
    };*/






















